#ifndef _SPREAD_HH_
#define _SPREAD_HH_
#include "Bfs.hh"


void update_path_potential();



template<typename _Action, typename _Condition>
void spread(State & s, Location loc, unsigned maxdepth, _Action __action, _Condition __condition)
{
  std::vector<std::vector<bool> > visited(s.rows, std::vector<bool>(s.cols, 0));
  
  // push starting location
  std::queue<Ploc> q;
  q.push(Ploc(loc,0));
  visited[loc.row][loc.col] = true;
 
  while(!q.empty())
    {
      Ploc ploc = q.front();
      __action(s,ploc);
      q.pop();

      if(ploc.depth<maxdepth)
	{
	  for(int d=0; d<TDIRECTIONS; d++)
	    {
	      Location newloc = s.getLocation(ploc, d);
	      if(__condition(s,newloc) and !visited[newloc.row][newloc.col])
		{
		  q.push(Ploc(newloc,ploc.depth+1));
		  visited[newloc.row][newloc.col] = true;
		}
	    }
	}
    }
}

template<typename _Action>
void spread(State & s, Location loc, unsigned maxdepth, _Action __action)
{
	walking_condition_t walk_cond;
	spread(s, loc, maxdepth, __action, walk_cond);
}

template<typename _Action>
void fly(State & s, Location loc, unsigned maxdepth, _Action __action)
{
	flying_condition_t fly_cond;
	spread(s, loc, maxdepth, __action, fly_cond);
}





struct update_value_circle_t
{
  double w;
  unsigned depth;

  update_value_circle_t(double _w,unsigned _depth) : w(_w),depth(_depth) {}
  
  void operator()(State & s, Ploc & ploc)
  {
    if(ploc.depth >= depth)
      s.location(ploc).value += w / (1.0 + ploc.depth - depth);
  }

};



struct update_value_disc_t
{
  double w;

  update_value_disc_t(double _w,unsigned _depth) : w(_w) {}
  
  void operator()(State & s, Ploc & ploc)
  {
    s.location(ploc).value += w;
  }

};




void set_values(State & s, 
		double foodw, double friendw, double hillw, double myhillw);

#endif /* _SPREAD_HH_ */
